package groups

import (
	"strings"
	"time"

	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"

	"github.com/gin-gonic/gin"
	"github.com/pkg/errors"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/app/ginsrv/api/base"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/columnd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/groupd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/infod"
)

func createGroupsCtrl(d core.CmsDomain) *groupCtrl {
	return &groupCtrl{
		BaseContrl: base.BaseContrl{
			Domain: d,
		},
		column: d.Column(),
		car:    d.Column().ColumnAggregateRoot(),
		gar:    d.Group().GroupAggregateRoot(),
		iar:    d.Info().InfoAggregateRoot(),
	}
}

// GroupSearch 查询条件
type GroupSearch struct {
	// Owner Org 如果都为空 :
	// 	 Range 0 查询所有信息包含 所有者和所属组织的信息
	// 	Range  1 查询除所属组织所属用户以外的信息
	// Owner Org 任何一个不为空：
	// 	  Range 参数失效
	Range  int              `form:"range"`  // 匹配范围
	Owner  string           `form:"owner"`  // 匹配所有者
	Org    string           `form:"org"`    // 匹配所属组织
	Kind   groupd.GroupKind `form:"kind"`   // 匹配信息组类型 类型（0,手动，1自动 -1 所有）
	Key    string           `form:"key"`    // 匹配信息组名称
	Status groupd.GStatus   `form:"status"` // -2 为全部 状态 -1 删除  0 停止  1 收集
}
type groupCtrl struct {
	base.BaseContrl
	column columnd.ColumnDomain
	car    columnd.ColumnAggregateRoot
	gar    groupd.GroupAggregateRoot
	iar    infod.InfoAggregateRoot
}

// 获取query中的信息组查询参数
func (c groupCtrl) getGrouSearch(ctx *gin.Context) (result groupd.GroupSearch, err error) {
	result.Range = c.GetIntByQuery(ctx, "range", 0)
	result.Owner = ctx.DefaultQuery("owner", "")
	result.Org = ctx.DefaultQuery("org", "")
	result.Key = ctx.DefaultQuery("key", "")
	result.Kind = groupd.GroupKind(c.GetIntByQuery(ctx, "kind", int(groupd.GroupKindAll)))
	as := c.GetIntArrayByQuery(ctx, "status", nil)
	if len(as) > 0 {
		for _, v := range as {
			result.Status = append(result.Status, groupd.GStatus(v))
		}
	}

	out := ctx.QueryArray("flags")
	for _, v := range out {
		if v = strings.Trim(v, " "); v != "" {
			result.Flags = append(result.Flags, strings.Trim(v, " "))
		}
	}

	return
}

// 分页获取信息组列表
func (c groupCtrl) getGroupPageList(ctx *gin.Context) {

	page := c.GetPageInfo(ctx, common.PageModeNum)
	dctx := c.DDDContext(ctx)
	sch, err := c.getGrouSearch(ctx)
	if err != nil {
		c.ErrBadRequestByBind(ctx, 1, err)
		return
	}
	pr, cs, err := c.gar.QueryPage(dctx, sch, page)
	if err != nil {
		c.ErrServerError(ctx, 1, "查找信息组失败", errors.Wrap(err, "查找信息组失败."))
		return
	}
	if cs == nil {
		cs = make([]groupd.GroupAggregate, 0)
	}
	c.SuccessPage(ctx, page, pr, cs)
}

// 获取信息组信息
func (c groupCtrl) getGroup(ctx *gin.Context) {

	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, err := c.gar.GetGroup(dctx, groupid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查找信息组失败", errors.Wrapf(err, "检测信息组(%v)是否存在失败：%v", groupid, err))
		return
	}
	if ga == nil {
		c.ErrNotFound(ctx, 3, "信息组不存在", nil)
		return
	}
	c.Success(ctx, ga)
}

// 获取信息组信息
func (c groupCtrl) getGroupDesc(ctx *gin.Context) {

	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, err := c.gar.GetGroup(dctx, groupid)
	if err != nil {
		c.ErrServerError(ctx, 2, "查找信息组失败", errors.Wrapf(err, "检测信息组(%v)是否存在失败：%v", groupid, err))
		return
	}
	if ga == nil {
		c.ErrNotFound(ctx, 3, "信息组不存在", nil)
		return
	}
	c.Success(ctx, ga.GroupDesc)
}

// ReqGroupDesc 新增信息组请求
type ReqGroupDesc struct {
	Name      string   `json:"name" binding:"required,max=30"`
	ShortName string   `json:"short_name" binding:"required,max=10"`
	Kind      int      `json:"kind"`
	Icon      []string `json:"icon"`
	Desc      string   `json:"desc" binding:"max=500"`
	Org       string   `json:"org" binding:"max=40"`
	Owner     string   `json:"owner" binding:"omitempty,max=40" `
}

// To 转换为 groupd.GroupDesc
func (r ReqGroupDesc) To() groupd.GroupDesc {
	return groupd.GroupDesc{
		ShortName: r.ShortName,
		Name:      r.Name,
		Icon:      r.Icon,
		Desc:      r.Desc,
		Kind:      groupd.GroupKind(r.Kind),
		Org:       r.Org,
		Owner:     r.Owner,
	}
}
func (c groupCtrl) add(ctx *gin.Context) {
	var req ReqGroupDesc

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 1, err)
		return
	}
	dctx := c.DDDContext(ctx)
	desc := req.To()

	ok, err := c.gar.ExistNameByDesc(dctx, "", desc)
	if err != nil {
		c.ErrServerError(ctx, 2, "保存失败", errors.Wrap(err, "信息组名称是否存在"))
		return
	}
	if ok {
		c.ErrBadRequest(ctx, 3, "信息组名称已经存在")
		return
	}
	id, err := c.gar.AddGroup(dctx, desc)
	if err != nil {
		c.ErrServerError(ctx, 4, "新增失败", errors.Wrap(err, "新增信息组失败："))
		return
	}
	c.Success(ctx, map[string]interface{}{"group_id": id})
}

// 获取栏目控制参数
func (c groupCtrl) getGroupCtrl(ctx *gin.Context) {

	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	ci := &groupCtrlInfo{}
	ci.Full(ga.GroupCtlParam)
	for i := 0; i < len(ci.Rules); i++ {
		cid := ci.Rules[i].ColumnID
		if cid == "" {
			continue
		}
		ca, err := c.car.GetColumn(dctx, cid)
		if err != nil {
			c.ErrServerError(ctx, 6, "保存失败", errors.Wrapf(err, "修改信息组(%v)控制参数失败：", groupid))
			return
		}

		ci.Rules[i].ColumnName = ca.Name
	}
	c.Success(ctx, ci)
}

// groupCtrlInfo 更新信息组控制参数请求
type groupCtrlInfo struct {
	InfoWeight int      `json:"info_weight"` // 权重模式 0.保持收录信息的权重 ，1.默认信息的权重0，
	Rules      Rules    `json:"rules"`       // 组规则
	Flags      []string `json:"flags"`       // 用户自行定义组标识
}

// To 装换为 groupd.GroupCtlParam
func (r groupCtrlInfo) To() (gc groupd.GroupCtlParam) {
	gc.InfoWeight = r.InfoWeight
	gc.Flags = r.Flags
	if r.Rules != nil {
		gc.Rules = r.Rules.To()
	}
	return
}

// To 装换为 groupd.GroupCtlParam
func (r *groupCtrlInfo) Full(gc groupd.GroupCtlParam) {
	r.InfoWeight = gc.InfoWeight
	r.Flags = gc.Flags
	if gc.Rules != nil {
		(&r.Rules).Full(gc.Rules)
	}
	return
}

// Rules 规则组
type Rules []Rule

// Full 填充值
func (r *Rules) Full(grs []groupd.Rule) {
	*r = make(Rules, 0, len(grs))
	for _, v := range grs {
		*r = append(*r, Rule{
			ColumnID: v.ColumnID,
			Org:      v.Org,
			Own:      v.Own,
			Key:      v.Key,
			Tags:     v.Tags,
		})
	}
	return
}

// To 转换为groupd.Rule
func (r Rules) To() (grs []groupd.Rule) {
	grs = make([]groupd.Rule, 0, len(r))
	for _, v := range r {
		grs = append(grs, v.To())
	}
	return
}

// Rule 组规则定义
type Rule struct {
	ColumnID   string   `json:"column_id,omitempty"`   // 栏目
	ColumnName string   `json:"column_name,omitempty"` // 栏目名称
	Org        string   `json:"org,omitempty"`         // 组织
	Own        string   `json:"own,omitempty"`         // 所有者
	Key        string   `json:"key,omitempty"`         // 关键字		针对信息内的文本内容做全文检索
	Tags       []string `json:"tags,omitempty"`        // 标签		完全匹配所有标签

}

// To 转换为groupd.Rule
func (r Rule) To() groupd.Rule {
	return groupd.Rule{
		ColumnID: r.ColumnID,
		Org:      r.Org,
		Own:      r.Own,
		Key:      r.Key,
		Tags:     r.Tags,
	}
}

func (c groupCtrl) updateCtrl(ctx *gin.Context) {
	var req groupCtrlInfo

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 1, err)
		return
	}
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	ctl := req.To()
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	err := ga.UpdateCtlParam(dctx, ctl)
	if err != nil {
		c.ErrServerError(ctx, 6, "保存失败", errors.Wrapf(err, "修改信息组(%v)控制参数失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}

func (c groupCtrl) updateDesc(ctx *gin.Context) {
	var req ReqGroupDesc

	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 1, err)
		return
	}
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 2, "请求参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	desc := req.To()

	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	ok, err := c.gar.ExistNameByDesc(dctx, groupid, desc)
	if err != nil {

		c.ErrServerError(ctx, 5, "检测信息组名称是否存在失败", errors.Wrapf(err, "检测信息组(%v)名称是否存在失败:", groupid))
		return
	}
	if ok {
		c.ErrBadRequest(ctx, 6, "信息组名称已经存在", nil)
		return
	}
	err = ga.UpdateDesc(dctx, desc)
	if err != nil {
		c.ErrServerError(ctx, 7, "保存失败", errors.Wrapf(err, "修改信息组(%v)失败.", groupid))
		return
	}
	c.Success(ctx, nil)
}

func (c groupCtrl) delete(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	if ga.InfoNum > 0 {
		c.ErrBadRequest(ctx, 4, "信息组下存在信息内容，不能删除", nil)
		return
	}
	err := ga.Delete(dctx)
	if err != nil {
		c.ErrServerError(ctx, 5, "删除失败", errors.Wrapf(err, "删除信息组(%v)失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}

func (c groupCtrl) destroy(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, err := c.gar.GetGroup(dctx, groupid)
	if err != nil {
		c.ErrServerError(ctx, 2, "彻底删除失败", errors.Wrapf(err, "检测信息组(%v)是否存在失败：", groupid))
		return
	}
	if ga == nil {
		c.ErrNotFound(ctx, 3, "信息组不存在", nil)
		return
	}
	if ga.InfoNum > 0 {
		c.ErrBadRequest(ctx, 4, "信息组下存在信息内容，不能彻底删除", nil)
		return
	}
	err = ga.Destroy(dctx)
	if err != nil {
		c.ErrServerError(ctx, 5, "彻底删除失败", errors.Wrapf(err, "彻底删除信息组(%v)失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}

func (c groupCtrl) recover(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, err := c.gar.GetGroup(dctx, groupid)
	if err != nil {
		c.ErrServerError(ctx, 2, "恢复失败", errors.Wrapf(err, "检测信息组(%v)是否存在失败：", groupid))
		return
	}
	if ga == nil {
		c.ErrNotFound(ctx, 3, "信息组不存在", nil)
		return
	}
	if ga.Status != groupd.GSDeleted {
		c.ErrBadRequest(ctx, 4, "信息组不是删除状态不能恢复", nil)
		return
	}
	err = ga.Recover(dctx)
	if err != nil {
		c.ErrServerError(ctx, 5, "彻底删除失败", errors.Wrapf(err, "彻底删除信息组(%v)失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}

func (c groupCtrl) stopCollecting(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	dctx := c.DDDContext(ctx)
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	if ga.Status == groupd.GSStop {
		c.Success(ctx, nil)
		return
	}
	if ga.Status != groupd.GSNormal {
		c.ErrBadRequest(ctx, 4, "信息组状态不对，可能已经被删除", nil)
		return
	}
	if err := ga.StopCollecting(dctx); err != nil {
		c.ErrServerError(ctx, 5, "停止收集信息失败", errors.Wrapf(err, "信息组(%v)停止收集信息失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}
func (c groupCtrl) starCollecting(ctx *gin.Context) {
	groupid := ctx.Param("groupid")

	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	if ga.Status == groupd.GSNormal {
		c.Success(ctx, nil)
		return
	}
	if ga.Status != groupd.GSStop {
		c.ErrBadRequest(ctx, 4, "信息组状态不对，可能已经被删除", nil)
		return
	}
	if err := ga.StartCollecting(dctx); err != nil {
		c.ErrServerError(ctx, 5, "开始收集信息失败", errors.Wrapf(err, "信息组(%v)开始收集信息失败：", groupid))
		return
	}
	c.Success(ctx, nil)
}

// groupInfo 组信息
type groupInfo struct {
	GIID        string    `json:"giid"`         // 唯一标志
	GroupID     string    `json:"group_id"`     // 信息组编码
	GroupName   string    `json:"group_name"`   // 组名称
	InfoID      string    `json:"info_id"`      // 信息编码
	Title       string    `json:"title"`        // 信息标题
	ColumnID    string    `json:"column_id"`    // 信息所在栏目
	ColumnName  string    `json:"column_name"`  // 信息所在栏目名称
	PublishTime time.Time `json:"publish_time"` // 信息所在时间
	Weight      int       `json:"weight"`       // 权重
	Seq         string    `json:"Seq"`          // 排序唯一
	CreTime     time.Time `json:"cre_time"`     // 加入时间
}

func (g *groupInfo) full(info groupd.GroupInfoEntity) {
	g.GIID = info.GIID
	g.GroupID = info.GroupID
	g.InfoID = info.InfoID
	g.Title = info.Title
	g.ColumnID = info.ColumnID
	g.ColumnName = info.ColumnName
	g.PublishTime = info.PublishTime
	g.Weight = info.Weight
	g.Seq = info.Seq
	g.CreTime = info.CreTime
}

// 分页获取信息组列表
func (c groupCtrl) getGroupInfoPageList(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	page := c.GetPageInfo(ctx, common.PageModeNum)
	dctx := c.DDDContext(ctx)

	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	pr, cs, err := ga.QueryInfoPage(dctx, page)
	if err != nil {
		c.ErrServerError(ctx, 5, "查找信息组失败", errors.Wrap(err, "查找信息组失败."))
		return
	}
	gis := make([]groupInfo, 0, len(cs))
	for _, v := range cs {
		gi := &groupInfo{}
		gi.full(v)
		gi.GroupName = ga.Name
		gis = append(gis, *gi)
	}
	c.SuccessPage(ctx, page, pr, gis)
}

// 分页获取信息组列表
func (c groupCtrl) getGroupExistsInfos(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误", nil)
		return
	}
	infoids := c.ParamArray(ctx, "ids")
	if len(infoids) == 0 {
		c.ErrBadRequest(ctx, 2, "请求参数错误，没有指定信息编号")
	}
	dctx := c.DDDContext(ctx)

	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	rs, err := ga.ExistsForInfo(dctx, infoids)
	if err != nil {
		c.ErrServerError(ctx, 5, "查找信息组失败", errors.Wrap(err, "查找信息组失败."))
		return
	}
	c.Success(ctx, rs)
}

// 向组内追加信息
func (c groupCtrl) appendGIInfos(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	ids := c.ParamArray(ctx, "infoids")
	if len(ids) == 0 {
		c.ErrBadRequest(ctx, 2, "请求参数错误")
		return
	}

	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	rs, err := c.iar.FullInfos(dctx, ids)
	if err != nil {
		c.ErrServerError(ctx, 6, "查找要添加的信息内容失败", errors.Wrapf(err, "查找要添加的信息(%v)内容失败失败：", ids))
		return
	}
	gis := make([]groupd.GroupInfoDesc, 0, len(rs))
	for _, v := range rs {

		gis = append(gis, groupd.WrapIa2Gid(dctx, ga, &v, c.car))
	}
	err = ga.AppendInfos(dctx, gis)

	if err != nil {
		c.ErrServerError(ctx, 5, "组内追加信息失败", errors.Wrap(err, "组内追加信息失败."))
		return
	}
	c.Success(ctx, nil)
}

// 删除组内信息
func (c groupCtrl) deleteGIInfos(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	ids := c.ParamArray(ctx, "infoids")
	if len(ids) == 0 {
		c.ErrBadRequest(ctx, 2, "请求参数错误")
		return
	}

	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}

	if err := ga.DeleteInfos(dctx, ids); err != nil {
		c.ErrServerError(ctx, 5, "删除组内信息失败", errors.Wrap(err, "删除组内信息失败."))
		return
	}
	c.Success(ctx, nil)
}

type reqChgGIWeight struct {
	Weight int `json:"weight"`
}

func (c groupCtrl) chgGIWeight(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	giid := ctx.Param("giid")
	if giid == "" {
		c.ErrBadRequest(ctx, 2, "请求参数错误")
		return
	}
	var req reqChgGIWeight
	if err := ctx.BindJSON(&req); err != nil {
		c.ErrBadRequestByBind(ctx, 3, err)
		return
	}

	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	if err := ga.UpdateInfoWeight(dctx, giid, req.Weight); err != nil {
		c.ErrServerError(ctx, 21, "更新组内信息权重失败", errors.Wrapf(err, "更新组(%v)内信息(%v)权重失败：%v", groupid, giid, err))
		return
	}
	c.Success(ctx, nil)
	return
}
func (c groupCtrl) emptyGIInfo(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}

	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	if err := ga.Empty(dctx); err != nil {
		c.ErrServerError(ctx, 2, "清空组内信息失败", errors.Wrapf(err, "清空组内信息(%v)失败：%v", groupid, err))
		return
	}
	c.Success(ctx, nil)
	return
}
func (c groupCtrl) refreshGIInfo(ctx *gin.Context) {
	groupid := ctx.Param("groupid")
	if groupid == "" {
		c.ErrBadRequest(ctx, 1, "请求参数错误")
		return
	}
	dctx := c.DDDContext(ctx)
	ga, ok := c.getCheckGroup(ctx, dctx, groupid)
	if !ok {
		return
	}
	groupd.RefreshGroupInfo(ga, c.iar, c.car)
	c.Success(ctx, "刷新中请耐心等待")
	return
}

func (c groupCtrl) getCheckGroup(ctx *gin.Context, dctx ddd.Context, groupid string) (ga *groupd.GroupAggregate, ok bool) {
	ga, err := c.gar.GetGroup(dctx, groupid)
	if err != nil {
		c.ErrServerError(ctx, 21, "获取信息组失败", errors.Wrapf(err, "检测信息组(%v)是否存在失败：", groupid))
		return
	}
	if ga == nil {
		c.ErrNotFound(ctx, 22, "信息组不存在", nil)
		return
	}
	if ga.Status == groupd.GSDeleted {
		c.ErrBadRequest(ctx, 23, "信息组已经被删除")
		return
	}
	ok = true
	return
}
